package cn.coder.jdbc2.config.builder;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import cn.coder.jdbc2.config.Configuration;
import cn.coder.jdbc2.core.JdbcDataSource;

public class XmlConfigBuilder {

	private InputStream inputStream;
	private Configuration configuration;

	public XmlConfigBuilder(InputStream inputStream) {
		this.inputStream = inputStream;
		this.configuration = new Configuration();
	}

	public Configuration parse(InputStream inputStream) {
		Document document = null;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			// 禁用外部实体，防止XXE
			factory.setExpandEntityReferences(false);
			document = factory.newDocumentBuilder().parse(this.inputStream);
		} catch (SAXException | IOException | ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (document != null) {
			parseConfiguration(document.getDocumentElement());
		}

		return configuration;
	}

	public Configuration parse() {
		return parse(inputStream);
	}

	private void parseConfiguration(Element element) {
		// TODO Auto-generated method stub
		// 解析<environments>
		parseEnvironments(element.getElementsByTagName("environments"));
		// 解析<mappers>
		parseMappers(element.getElementsByTagName("mappers"));
	}

	private void parseEnvironments(NodeList nodeList) {
		// TODO Auto-generated method stub
		if (nodeList.getLength() == 0)
			return;
		Element ele = (Element) nodeList.item(0);
		String attr = ele.getAttribute("default");
		NodeList elements = ele.getElementsByTagName("environment");

		if (attr != null) {
			for (int i = 0; i < elements.getLength(); i++) {
				if (elements.item(i) instanceof Element) {
					String eleId = ((Element) elements.item(i)).getAttribute("id");
					if (eleId != null && eleId.equals(attr)) {
						parseDataSource(ele.getElementsByTagName("dataSource"));

						break;
					}
				}
			}
		} else {
			throw new RuntimeException("environments标签的default属性不能为空");
		}

	}

	private void parseDataSource(NodeList nodeList) {
		// TODO Auto-generated method stub
		if (nodeList.getLength() == 0)
			return;
		Element ele = (Element) nodeList.item(0);
		String type = ele.getAttribute("type");
		if (type == null || type.trim().equals(""))
			type = "DBCP";

		Properties prop = new Properties();
		/*
		 * for (Element ele : element.elements("property")) {
		 * 
		 * }
		 */
		NodeList elements = ele.getElementsByTagName("property");
		for (int i = 0; i < elements.getLength(); i++) {
			if (elements.item(i) instanceof Element) {
				String name = ((Element) elements.item(i)).getAttribute("name");
				String value = ((Element) elements.item(i)).getAttribute("value");
				prop.setProperty(name, value);
			}
		}

		// 封装数据源对象
		JdbcDataSource dataSource = new JdbcDataSource(prop);
		// dataSource.setDriverClassName(prop.getProperty("driver"));
		// dataSource.setUrl(prop.getProperty("url"));
		// dataSource.setUsername(prop.getProperty("username"));
		// dataSource.setPassword(prop.getProperty("password"));

		configuration.setDataSource(dataSource);
	}

	private void parseMappers(NodeList nodeList) {
		// TODO Auto-generated method stub
		if (nodeList.getLength() == 0)
			return;
		Element ele = (Element) nodeList.item(0);
		NodeList elements = ele.getElementsByTagName("mapper");
		for (int i = 0; i < elements.getLength(); i++) {
			if (elements.item(0) instanceof Element) {
				parseMapper((Element) elements.item(0));
			}
		}
	}

	private void parseMapper(Element element) {
		String resource = element.getAttribute("resource");
		InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource);
		XmlMapperBuilder parser = new XmlMapperBuilder(inputStream, configuration);
		parser.parse();
	}

}
